package middleware

import (
	"bytes"
	"encoding/json"
	"fmt"
	"googee/common/errorx"
	"googee/service/admin/rpc/sys"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/stores/redis"
	"github.com/zeromicro/go-zero/rest/httpx"
)

var ignoreUrls = map[string]bool{
	"/api/sys/sysLog/list":     true,
	"/api/sys/loginLog/delete": true,
	"/api/sys/sysLog/delete":   true,
	"/api/sys/job/list":        true,
	"/api/sys/user/list":       true,
	"/api/sys/role/list":       true,
}

type CheckUrlMiddleware struct {
	Redis *redis.Redis
	Sys   sys.Sys
	Mode  string
}

func NewCheckUrlMiddleware(Redis *redis.Redis, sys sys.Sys, mode string) *CheckUrlMiddleware {
	return &CheckUrlMiddleware{Redis: Redis, Sys: sys, Mode: mode}
}

func (m *CheckUrlMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		//判断请求header中是否携带了x-user-id
		userId := r.Context().Value("userId").(json.Number).String()
		if userId == "" {
			logx.Errorf("缺少必要参数x-user-id")
			httpx.Error(w, errorx.NewCodeError(50008, "缺少必要参数x-user-id"))
			return
		}

		userIdInt, err := strconv.ParseInt(userId, 10, 64)
		if err != nil {
			logx.Errorf("缺少必要参数x-user-id")
			httpx.Error(w, errorx.NewCodeError(50008, "缺少必要参数x-user-id"))
		}
		logx.Infof("userIdInt: %v", userIdInt)

		if r.RequestURI == "/api/sys/user/currentUser" ||
			r.RequestURI == "/api/sys/user/logout" ||
			r.RequestURI == "/api/sys/user/selectAllData" ||
			r.RequestURI == "/api/sys/role/queryMenuByRoleId" {
			logx.Infof("用户userId: %s,访问: %s路径", userId, r.RequestURI)
			next(w, r)
		} else {
			//获取用户能访问的url
			urls, err := m.Redis.Get(userId)
			if err != nil {
				logx.Errorf("用户：%s,获取redis连接异常", userId)
				httpx.Error(w, errorx.NewCodeError(50008, fmt.Sprintf("用户：%s,获取redis连接异常", userId)))
				return
			}

			if len(strings.TrimSpace(urls)) == 0 {
				logx.Errorf("用户userId: %s,还没有登录", userId)
				httpx.Error(w, errorx.NewCodeError(50008, fmt.Sprintf("用户userId: %s,还没有登录,请先登录", userId)))
				return
			}

			backUrls := strings.Split(urls, ",")

			b := false
			for _, url := range backUrls {
				suburls := strings.Split(url, ";")
				// logx.Infof("======> url=%v", url)
				// logx.Infof("======> suburls=%v", suburls)
				for _, suburl := range suburls {
					if suburl == r.RequestURI {
						b = true
						break
					}
				}
			}

			if b {
				logx.Infof("==========++++++++++> 用户userId: %s,访问: %s路径", userId, r.RequestURI)
				n := time.Now()
				params := ""
				method := r.Method
				if strings.ToUpper(method) == "POST" {
					body, _ := ioutil.ReadAll(r.Body)
					params = string(body)
					r.Body = ioutil.NopCloser(bytes.NewBuffer(body))

				} else {
					params = r.URL.RawQuery
				}
				//获得用户信息
				uinfo, err := m.Sys.UserInfo(r.Context(), &sys.InfoReq{
					UserId: userIdInt,
				})

				if err != nil {
					logx.Errorf("缺少必要参数x-user-id")
					httpx.Error(w, errorx.NewCodeError(50008, "缺少必要参数x-user-id"))
				}
				next(w, r)

				//调用sys rpc 写入系统访问日志
				if _, ok := ignoreUrls[r.RequestURI]; !ok {
					m.Sys.SysLogAdd(r.Context(), &sys.SysLogAddReq{
						UserName:  uinfo.Name,
						Method:    method,
						Operation: r.RequestURI,
						Params:    params,
						Time:      time.Since(n).Milliseconds(),
						Ip:        r.RemoteAddr,
						CreateBy:  uinfo.Name,
					})
				}
			} else {
				logx.Errorf("用户userId: %s,没有访问: %s路径的权限", userId, r.RequestURI)
				if m.Mode == "dev" {
					httpx.Error(w, errorx.NewCodeError(50015, fmt.Sprintf("用户userId: %s,没有访问: %s,路径的的权限,请联系管理员", userId, r.RequestURI)))
				} else {
					httpx.Error(w, errorx.NewCodeError(50015, "没有使用当前功能权限,请联系管理员"))
				}
				return
			}

		}
	}
}
